#include "ft6x36_upgrade_firmware.h"
#include "ft6x36.h"

#if USE_FT6X36
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
#include "../../board.h"
#include "../common/i2c.h"
#include "../common/lv_pm.h"
#include "lvgl/src/lv_core/lv_group.h"
#include "lvgl/src/lv_misc/lv_tsrb.h"


uint8_t fw_file_FT3169_240x240[] = {
#include "FT3169_240x240_V0x03_D0x03_20221117_app.i" /* module, lcd dev id = 0x9307 */
};

#define FTS_MODULE_ID                 0x0000
#define FTS_MODULE_NAME               ""

struct upgrade_module module_list[] = {
    {FTS_MODULE_ID, FTS_MODULE_NAME, fw_file_FT3169_240x240, sizeof(fw_file_FT3169_240x240)}, /* module, lcd dev id = 0x9307 */
    //{FTS_MODULE_ID, FTS_MODULE_NAME, fw_file_FTxxxx_128X128, sizeof(fw_file_FTxxxx_128X128)}, /* module, lcd dev id = 0x9107 */
};

struct fts_upgrade fwupgrade;

/*
 * lcd+tp module： need module id for tp firmware upgrade
 * but these module no module id. 
 * so whether ft6x36 should be firmware upgraded, temperally use lcd dev id to judge.
 * old 240_240: st7789v + ft6x36(no need tp firmware upgrade)
 * new 240_240: gc9307  + ft6x36(need tp firmware upgrade, firmware bin: indev/Ft3169_240_240_V0x03_20221117.app.i)
 * new 128_128: gc9107  + ft6x36(need tp firmware upgrade, no firmware upgrade bin yet)
 */
static struct upgrade_module *get_module_info(void)
{
    if (lcd_get_dev_id() == 0x9307) {
        return &module_list[0];
    }
#if 0
    else if (lcd_get_dev_id() == 0x9107) {
        return &module_list[1];
    }
#endif
    return NULL;
}


static int fts_fwupg_get_fw_file(struct fts_upgrade *upg)
{
    struct upgrade_module *info = get_module_info();
    if(info == NULL) {
        return -1;
    }

    upg->module_info = info;
    upg->fw = upg->module_info->fw_file;
    upg->fw_length = upg->module_info->fw_len;
    // fts_fwupg_init_func
    upg->func = &upgrade_func_ft6x36;

    return 0;
}

int fts_fwupg_reset_in_boot(void)
{
    int ret = 0;

    printf("reset in boot environment");
    ret = i2c_write_reg(I2C_MASTER_CI2C1, FT6X36_I2C_ADDR, FTS_CMD_RESET, 1, 0);
    if (ret < 0) {
        printf("pram/rom/bootloader reset cmd write fail");
        return ret;
    }

    uos_sleep(FTS_DELAY_UPGRADE_RESET/5);
    return 0;
}

static int fts_fwupg_get_ver_in_tp(unsigned char *ver)
{
    int ret = 0;

    if (NULL == ver) {
        printf("ver is NULL");
        return -1;
    }

    ret = i2c_read_reg(I2C_MASTER_CI2C1, FT6X36_I2C_ADDR, FTS_REG_FW_VER, ver, 0);

    if (ret < 0) {
        printf("read fw ver from tp fail");
        return ret;
    }

    return 0;
}

static int fts_fwupg_get_ver_in_host(struct fts_upgrade *upg, unsigned char *ver)
{
    if ((!upg) || (!upg->func) || (!upg->fw) || (!ver)) {
        printf("upgrade/func/fw/ver is NULL\n");
        return -1;
    }

    if (upg->fw_length < upg->func->fwveroff) {
        printf("fw len(0x%0x) < fw ver offset(0x%x)\n",
                  upg->fw_length, upg->func->fwveroff);
        return -1;
    }

    printf("fw version offset:0x%x", upg->func->fwveroff);
    *ver = upg->fw[upg->func->fwveroff];
    return 0;
}

static bool fts_fwupg_need_upgrade(struct fts_upgrade *upg)
{
    int ret = 0;
    uint8_t fw_ver_in_host = 0;
    uint8_t fw_ver_in_tp = 0;

    ret = fts_fwupg_get_ver_in_host(upg, &fw_ver_in_host);
    if (ret < 0) {
        printf("get fw ver in host fail");
        return false;
    }

    ret = fts_fwupg_get_ver_in_tp(&fw_ver_in_tp);
    if (ret < 0) {
        printf("get fw ver in tp fail");
        return false;
    }

    printf("fw version in tp:%x, host:%x", fw_ver_in_tp, fw_ver_in_host);

    if (fw_ver_in_tp != fw_ver_in_host) {
        return true;
    }
    else {
        //printf("fw ver same, no need upgrade fw");
        return false;
    }
}

int fts_fwupg_upgrade(struct fts_upgrade *upg)
{
    int ret = 0;
    bool upgrade_flag = false;
    int upgrade_try = 0;
    unsigned char ver = 0;

    if ((NULL == upg) || (NULL == upg->func)) {
        printf("fw upg/upg->func is null\n");

        return -1;
    }

    upgrade_flag = fts_fwupg_need_upgrade(upg);
    cplog_printf("tp fw upgrade flag:%d\n", upgrade_flag);

    if(false == upgrade_flag) {
        return 0;
    }

    printf("********************FTS enter upgrade********************\n");
    do {
        upgrade_try++;

        printf("upgrade fw app(times:%d)", upgrade_try);
        if (upg->func->upgrade) {
            ret = upg->func->upgrade(upg->fw, upg->fw_length);
            if (ret < 0) {
                fts_fwupg_reset_in_boot();
            } else {
                fts_fwupg_get_ver_in_tp(&ver);
                printf("success upgrade to fw version %02x", ver);
                break;
            }
        } else {
            printf("upgrade func/upgrade is null, return immediately");
            ret = -1;
            break;
        }
    } while (upgrade_try < 2);


    if (ret < 0) {
        cplog_printf("**********tp fw(app/param) upgrade failed**********\n");
    }
    else {
        cplog_printf("**********tp fw(app/param) no upgrade/upgrade success**********\n");
    }

    return ret;
}

void fts_fwupg_work(void)
{
    int ret = 0;
    struct fts_upgrade *upg = &fwupgrade;
#if !FTS_AUTO_UPGRADE_EN
        printf("FTS_AUTO_UPGRADE_EN is disabled, not upgrade when power on");

        return;
#endif

    ret = fts_fwupg_get_fw_file(upg);
    if (ret < 0) {
        //printf("no firmware no need upgrad\n");
        goto error;
    }

    ft6x36_disable_irq();
    fts_fwupg_upgrade(upg);
    ft6x36_enable_irq();

error:
    return;
}

#endif
